﻿#pragma once

#include <xy/geom/camera.h>
#include <xy/utils/factory.h>

namespace xy
{

namespace ais
{

// 前向声明
class object;

class renderer
{
  public:
    /**
     * @brief 绘制物体
     *
     * @param[in] obj
     */
    virtual void draw(const object *obj) const = 0;

    /**
     * @brief 刷新渲染器
     *
     * @param[in] obj
     */
    virtual void update(const object *obj) = 0;
};

using renderer_factory = utils::generic_factory<renderer, std::string, std::function<renderer *()>>;

struct msg
{
    /**
     * @brief 访问接口
     *
     * @param[in] visitor
     */
    virtual void accept(object *visitor) = 0;

    /**
     * @brief 虚析构函数
     *
     */
    virtual ~msg() = default;
};

template <class Derived> struct msg_impl : msg
{
    /**
     * @brief CRTP 模式
     *
     * @param[in] visitor
     */
    void accept(object *visitor) override;
};

struct msg_init : msg_impl<msg_init>
{
    std::shared_ptr<renderer_factory> factory;
};

struct msg_update : msg_impl<msg_update>
{
};

struct msg_paint : msg_impl<msg_paint>
{
};

struct msg_visible : msg_impl<msg_visible>
{
    bool show{false};
};

struct msg_move : msg_impl<msg_move>
{
    geom::vec3f pos; // 鼠标点击位置对应的空间坐标
    geom::vec3f dir; // 鼠标点击位置对应的视角方向
};

struct msg_mouse : msg_impl<msg_mouse>
{
    enum Button
    {
        Left,
        Middle,
        Right
    };

    enum Status
    {
        Move,
        Press,
        Release
    };

    float depth{1.0f};                                     // 记录深度
    Button button{Left};                                   // 左中右
    Status status{Move};                                   // 悬停/点击/释放
    object *captured{nullptr};                             // 捕获对象
    object *hovered{nullptr};                              // 悬停对象
    object *pressed{nullptr};                              // 按下对象
    geom::vec2f pressPos{};                                // 点击位置
    geom::vec2f movePos{};                                 // 移动位置
    geom::vec2i windowSize{};                              // 窗口大小
    std::shared_ptr<geom::camera> camera;                  // 相机对象
    std::function<geom::vec3f(geom::vec3f)> screenMapping; // 坐标转换函数
    std::function<geom::vec3f(geom::vec2f)> spaceMapping;  // 坐标转换函数
};

struct msg_destroy : msg_impl<msg_destroy>
{
};

} // namespace ais

} // namespace xy
